Skip to content

fix: restore reserved suffix stripping in PrometheusNaming.sanitizeMetricName()#2124

Merged
zeitlinger merged 1 commit into
prometheus:mainfrom
zeitlinger:fix/sanitize-metric-name-reserved-suffix
May 20, 2026
Merged

fix: restore reserved suffix stripping in PrometheusNaming.sanitizeMetricName()#2124
zeitlinger merged 1 commit into
prometheus:mainfrom
zeitlinger:fix/sanitize-metric-name-reserved-suffix

Conversation

@zeitlinger

Copy link
Copy Markdown
Member

Fixes #2087.

Supersedes #2094 with the same fix on a clean, signed-off commit so the DCO
check can pass.

sanitizeMetricName() was simplified in 1.6.0 to return its input unchanged
because any non-empty UTF-8 string is now a valid metric name. That silently
broke downstream tools — notably the JMX Exporter and the simpleclient bridge —
that call sanitizeMetricName() to normalize external names before passing them
to snapshot builders.

The missing stripping means a JMX attribute that produces
kafka_consumer_request_total as a raw name is no longer sanitized to
kafka_consumer_request. With inferCounterTypeFromName: true this triggers
unintended counter-type inference; with it false the metric is stored under the
wrong name, breaking exact-name registry lookups.

Changes

  • Restore RESERVED_METRIC_NAME_SUFFIXES and the iterative suffix-stripping loop
    in PrometheusNaming.sanitizeMetricName().
  • Keep the exact-match case, for example "_total" -> "total", in a dedicated
    pre-pass before the stripping loop.
  • Update PrometheusNamingTest and MetricMetadataTest expectations.
  • Add regression coverage for the JMX Exporter scenario and dot-variant corner
    case, for example .total.
// Before fix: suffix preserved -> metric stored as "kafka_consumer_request_total"
PrometheusNaming.sanitizeMetricName("kafka_consumer_request_total");

// After fix: suffix stripped -> metric stored as "kafka_consumer_request"
PrometheusNaming.sanitizeMetricName("kafka_consumer_request_total");

Counter.builder().name("events_total") is unaffected because the builder API
does not go through sanitizeMetricName().

Validation

  • mise run build

Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
@zeitlinger zeitlinger merged commit 2d0f508 into prometheus:main May 20, 2026
10 checks passed
@zeitlinger zeitlinger deleted the fix/sanitize-metric-name-reserved-suffix branch May 20, 2026 09:53
zeitlinger added a commit that referenced this pull request May 22, 2026
Draft validation PR for the unmodified Micrometer compatibility story.

This intentionally does **not** depend on #2114. Vanilla Micrometer does
not use
the typed descriptor API and does not implement the #1800 registration
metadata
hooks, so this PR validates the patch-compatible path independently of
typed
descriptors.

This validates upstream `micrometer-metrics/micrometer@main` against:

- current `main`, which already includes #2100 and #2124 (reserved
suffix
  stripping in `PrometheusNaming.sanitizeMetricName()`).
- Micrometer compatibility test tooling/workflow from
zeitlinger#1.

Local validation:

- `mise run lint`
- `MICROMETER_DIR=/tmp/micrometer-compat-vanilla-2124 mise run
micrometer:test`

---------

Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
Co-authored-by: Jay DeLuca <jaydeluca4@gmail.com>
zeitlinger added a commit that referenced this pull request Jun 1, 2026
Adds typed metric family descriptors and typed metadata support for the
model snapshots.

This is the typed-descriptor branch for downstreams that want to provide
registration-time metadata explicitly. The #1800
Collector/MultiCollector registration metadata hooks are already
optional via default methods, so unmodified downstreams should not need
this PR just to keep working.

This PR now also deprecates the fragmented registration metadata API
(`getPrometheusName()`, `getMetricType()`, `getLabelNames()`, and
`getMetadata()` plus the `MultiCollector` variants) in favor of
`getMetricFamilyDescriptor()` / `getMetricFamilyDescriptors()`. The
deprecated methods remain bridged by default implementations for
compatibility.

Related validation:

- #2121 validates unmodified Micrometer independently of #2114, against
`main` + #2124.
- #2123 validates a Micrometer branch that explicitly uses
`MetricFamilyDescriptor` to implement the existing registration metadata
hooks without invoking scrape/sample callbacks during registration.

---------

Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
zeitlinger added a commit that referenced this pull request Jun 3, 2026
🤖 I have created a release *beep* *boop*
---


##
[1.7.0](v1.6.1...v1.7.0)
(2026-06-03)


### Features

* Add StableApi marker and API diff check
([#2168](#2168))
([768fd3a](768fd3a))
* add typed metric family descriptors
([#2114](#2114))
([9c3b097](9c3b097))
* track api-diff baseline via Renovate and store diffs in docs/apidiffs
([#2174](#2174))
([3adb890](3adb890))


### Bug Fixes

* **deps:** update dependency com.github.ben-manes.caffeine:caffeine to
v3.2.4 ([#2088](#2088))
([144eb61](144eb61))
* **deps:** update dependency io.dropwizard.metrics:metrics-core to
v4.2.39 ([#2139](#2139))
([5817d13](5817d13))
* **deps:** update dependency io.dropwizard.metrics5:metrics-core to
v5.0.7 ([#2140](#2140))
([261c451](261c451))
* **deps:** update dependency
io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom-alpha
to v2.28.0-alpha
([#2126](#2126))
([b62b5d0](b62b5d0))
* **deps:** update dependency
io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom-alpha
to v2.28.0-alpha
([#2127](#2127))
([e11ce3d](e11ce3d))
* **deps:** update dependency
io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom-alpha
to v2.28.1-alpha
([#2132](#2132))
([b09be38](b09be38))
* **deps:** update dependency
io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom-alpha
to v2.28.1-alpha
([#2133](#2133))
([a241c16](a241c16))
* **deps:** update dependency org.apache.tomcat.embed:tomcat-embed-core
to v11.0.22
([#2099](#2099))
([22125c5](22125c5))
* **deps:** update jetty monorepo to v12.1.10
([#2169](#2169))
([ddd3991](ddd3991))
* **deps:** update jetty monorepo to v12.1.9
([#2102](#2102))
([04bee70](04bee70))
* **deps:** update protobuf
([#2129](#2129))
([320538a](320538a))
* Reduce allocations for classic histogram buckets
([#2081](#2081))
([edd160a](edd160a))
* restore legacy suffix compatibility
([#2100](#2100))
([b2ae70f](b2ae70f))
* restore reserved suffix stripping in
`PrometheusNaming.sanitizeMetricName()`
([#2124](#2124))
([2d0f508](2d0f508))


### Performance Improvements

* Refactored sorting to use optimized sort algorithms
([#2161](#2161))
([25b94fc](25b94fc))


### Documentation

* clarify downstream adapter validation requirements
([#2101](#2101))
([ef8c75c](ef8c75c))
* Document OM2
([#2059](#2059))
([45d753c](45d753c))
* document PushGateway shading workaround
([#2106](#2106))
([8ca0eb8](8ca0eb8))

---
> [!IMPORTANT]
> Close and reopen this PR to trigger CI checks.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
jaydeluca pushed a commit that referenced this pull request Jun 4, 2026
…etricName()` (#2124)

Fixes #2087.

Supersedes #2094 with the same fix on a clean, signed-off commit so the
DCO
check can pass.

`sanitizeMetricName()` was simplified in 1.6.0 to return its input
unchanged
because any non-empty UTF-8 string is now a valid metric name. That
silently
broke downstream tools — notably the JMX Exporter and the simpleclient
bridge —
that call `sanitizeMetricName()` to normalize external names before
passing them
to snapshot builders.

The missing stripping means a JMX attribute that produces
`kafka_consumer_request_total` as a raw name is no longer sanitized to
`kafka_consumer_request`. With `inferCounterTypeFromName: true` this
triggers
unintended counter-type inference; with it `false` the metric is stored
under the
wrong name, breaking exact-name registry lookups.

## Changes

- Restore `RESERVED_METRIC_NAME_SUFFIXES` and the iterative
suffix-stripping loop
  in `PrometheusNaming.sanitizeMetricName()`.
- Keep the exact-match case, for example `"_total"` -> `"total"`, in a
dedicated
  pre-pass before the stripping loop.
- Update `PrometheusNamingTest` and `MetricMetadataTest` expectations.
- Add regression coverage for the JMX Exporter scenario and dot-variant
corner
  case, for example `.total`.

```java
// Before fix: suffix preserved -> metric stored as "kafka_consumer_request_total"
PrometheusNaming.sanitizeMetricName("kafka_consumer_request_total");

// After fix: suffix stripped -> metric stored as "kafka_consumer_request"
PrometheusNaming.sanitizeMetricName("kafka_consumer_request_total");
```

`Counter.builder().name("events_total")` is unaffected because the
builder API
does not go through `sanitizeMetricName()`.

## Validation

- `mise run build`

Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
Signed-off-by: Jay DeLuca <jaydeluca4@gmail.com>
jaydeluca added a commit that referenced this pull request Jun 4, 2026
Draft validation PR for the unmodified Micrometer compatibility story.

This intentionally does **not** depend on #2114. Vanilla Micrometer does
not use
the typed descriptor API and does not implement the #1800 registration
metadata
hooks, so this PR validates the patch-compatible path independently of
typed
descriptors.

This validates upstream `micrometer-metrics/micrometer@main` against:

- current `main`, which already includes #2100 and #2124 (reserved
suffix
  stripping in `PrometheusNaming.sanitizeMetricName()`).
- Micrometer compatibility test tooling/workflow from
zeitlinger#1.

Local validation:

- `mise run lint`
- `MICROMETER_DIR=/tmp/micrometer-compat-vanilla-2124 mise run
micrometer:test`

---------

Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
Co-authored-by: Jay DeLuca <jaydeluca4@gmail.com>
Signed-off-by: Jay DeLuca <jaydeluca4@gmail.com>
jaydeluca pushed a commit that referenced this pull request Jun 4, 2026
Adds typed metric family descriptors and typed metadata support for the
model snapshots.

This is the typed-descriptor branch for downstreams that want to provide
registration-time metadata explicitly. The #1800
Collector/MultiCollector registration metadata hooks are already
optional via default methods, so unmodified downstreams should not need
this PR just to keep working.

This PR now also deprecates the fragmented registration metadata API
(`getPrometheusName()`, `getMetricType()`, `getLabelNames()`, and
`getMetadata()` plus the `MultiCollector` variants) in favor of
`getMetricFamilyDescriptor()` / `getMetricFamilyDescriptors()`. The
deprecated methods remain bridged by default implementations for
compatibility.

Related validation:

- #2121 validates unmodified Micrometer independently of #2114, against
`main` + #2124.
- #2123 validates a Micrometer branch that explicitly uses
`MetricFamilyDescriptor` to implement the existing registration metadata
hooks without invoking scrape/sample callbacks during registration.

---------

Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
Signed-off-by: Jay DeLuca <jaydeluca4@gmail.com>
jaydeluca pushed a commit that referenced this pull request Jun 4, 2026
🤖 I have created a release *beep* *boop*
---

##
[1.7.0](v1.6.1...v1.7.0)
(2026-06-03)

### Features

* Add StableApi marker and API diff check
([#2168](#2168))
([768fd3a](768fd3a))
* add typed metric family descriptors
([#2114](#2114))
([9c3b097](9c3b097))
* track api-diff baseline via Renovate and store diffs in docs/apidiffs
([#2174](#2174))
([3adb890](3adb890))

### Bug Fixes

* **deps:** update dependency com.github.ben-manes.caffeine:caffeine to
v3.2.4 ([#2088](#2088))
([144eb61](144eb61))
* **deps:** update dependency io.dropwizard.metrics:metrics-core to
v4.2.39 ([#2139](#2139))
([5817d13](5817d13))
* **deps:** update dependency io.dropwizard.metrics5:metrics-core to
v5.0.7 ([#2140](#2140))
([261c451](261c451))
* **deps:** update dependency
io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom-alpha
to v2.28.0-alpha
([#2126](#2126))
([b62b5d0](b62b5d0))
* **deps:** update dependency
io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom-alpha
to v2.28.0-alpha
([#2127](#2127))
([e11ce3d](e11ce3d))
* **deps:** update dependency
io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom-alpha
to v2.28.1-alpha
([#2132](#2132))
([b09be38](b09be38))
* **deps:** update dependency
io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom-alpha
to v2.28.1-alpha
([#2133](#2133))
([a241c16](a241c16))
* **deps:** update dependency org.apache.tomcat.embed:tomcat-embed-core
to v11.0.22
([#2099](#2099))
([22125c5](22125c5))
* **deps:** update jetty monorepo to v12.1.10
([#2169](#2169))
([ddd3991](ddd3991))
* **deps:** update jetty monorepo to v12.1.9
([#2102](#2102))
([04bee70](04bee70))
* **deps:** update protobuf
([#2129](#2129))
([320538a](320538a))
* Reduce allocations for classic histogram buckets
([#2081](#2081))
([edd160a](edd160a))
* restore legacy suffix compatibility
([#2100](#2100))
([b2ae70f](b2ae70f))
* restore reserved suffix stripping in
`PrometheusNaming.sanitizeMetricName()`
([#2124](#2124))
([2d0f508](2d0f508))

### Performance Improvements

* Refactored sorting to use optimized sort algorithms
([#2161](#2161))
([25b94fc](25b94fc))

### Documentation

* clarify downstream adapter validation requirements
([#2101](#2101))
([ef8c75c](ef8c75c))
* Document OM2
([#2059](#2059))
([45d753c](45d753c))
* document PushGateway shading workaround
([#2106](#2106))
([8ca0eb8](8ca0eb8))

---
> [!IMPORTANT]
> Close and reopen this PR to trigger CI checks.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
Signed-off-by: Jay DeLuca <jaydeluca4@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Counter name/type inference changed in 1.6.1 for untyped metrics, breaking downstream expectation of UNKNOWN

2 participants